#!/usr/bin/env python3
# -*- encoding: utf-8 -*-


import numpy as np


# 恒等函数
def identify_function(x):
    return x


# 阶跃函数
def step_function(x):
    return np.array(x > 0, dtype=np.int)


# sigmoid函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


# ReLU函数
def relu(x):
    return np.maximum(0, x)


# softmax函数
def softmax(x):
    # ----------
    # *1*
    # 一次进行多个样本的训练，输出是A行B列的矩阵
    # A表示样本数，B表示输出数
    # 比如神经网络有2个输出，一次训练100个样本，则x如下：
    # x(1,1)        x(1,2)
    # x(2,1)        x(2,2)
    # ...           ...
    # x(100,1)      x(100,2)
    # ----------
    # *2*
    # 计算过程中为什么需要reshape？
    # (100,2)只能和(100,1)作四则运算，和(100,)则不可以
    # (100,)可能被认为是(1,100)吧
    if x.ndim == 2:
        x = x - np.max(x, axis=1).reshape(-1, 1)
        return np.exp(x) / np.sum(np.exp(x), axis=1).reshape(-1, 1)

    x = x - np.max(x)      # 溢出对策
    return np.exp(x) / np.sum(np.exp(x))


# softmax函数（来自书附带的示例）
def softmax_b(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    x = x - np.max(x)   # 溢出对策
    return np.exp(x) / np.sum(np.exp(x))


# 均方差
def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t) ** 2)


# 交叉熵误差
def cross_entropy_error(y, t):
    # 为了和下面axis=1一致
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    # 监督数据是one-hot-vector的情况下，转换为正确解标签的索引
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
